package org.xx.armory.db;


import java.util.List;
import java.util.Optional;

/**
 * 数据库访问会话。
 *
 * @author Haart
 */
public interface Session
        extends AutoCloseable {
    /**
     * 构造一个SQL参数构造器。
     *
     * @param name
     *         待添加的SQL参数的名字。
     * @return 会话本身。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符。
     */
    ParameterBuilder newParameter(
            String name
    );

    /**
     * 向会话中添加一个SQL参数。
     *
     * @param parameter
     *         待添加的SQL参数。
     * @throws IllegalArgumentException
     *         如果参数{@code parameter}是{@code null}。
     */
    void addParameter(
            Parameter parameter
    );

    /**
     * 清除所有的SQL参数。
     *
     * @return 会话本身。
     */
    Session clearParameters();

    /**
     * 设置要获取的数据集的第一个记录的序号。
     *
     * @param startRowIndex
     *         要获取的数据集的第一个记录的序号(从{@code 0}开始)。
     * @return 会话本身。
     */
    Session setStartRowIndex(
            int startRowIndex
    );

    /**
     * 设置要获取的数据集的最多记录数。
     *
     * @param maximumRows
     *         要获取的数据集的最多记录数。
     * @return 会话本身。
     */
    Session setMaximumRows(
            int maximumRows
    );

    /**
     * 设置每次查询抓取的最多记录数。
     *
     * @param fetchSize
     *         每次查询抓取的最多记录数。
     * @return 会话本身。
     * @throws IllegalArgumentException
     *         如果参数{@code fetchSize}小于0。
     */
    Session setFetchSize(
            int fetchSize
    );

    /**
     * 设置需要获取的自动生成的列的名称。
     *
     * @param autoKey
     *         需要获取的自动生成的列的名称，如果是{@code null}则看作空字符串。
     * @return 会话本身。
     */
    Session setAutoKey(
            String autoKey
    );

    /**
     * 执行SQL查询。
     *
     * @param <T>
     *         实体对象类型。
     * @param sql
     *         需要执行的SQL命令。
     * @param mapper
     *         用于将查询结果集映射到实体对象的映射类。
     * @return 查询结果列表, 包含所有被映射的实体类。
     * @throws NullPointerException
     *         如果参数{@code sql}或{@code mapper}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code sql}只包含空白字符。
     */
    <T> List<T> query(
            String sql,
            Mapper<T> mapper
    );

    /**
     * 执行SQL查询并获取单个实体。
     *
     * @param <T>
     *         实体对象类型。
     * @param sql
     *         需要执行的SQL命令。
     * @param mapper
     *         用于将查询结果集映射到实体对象的映射类。
     * @return 查询结果, 即使查询结果集包含多条记录也只返回第一个实体, 如果没有记录则返回{@code null}。
     * @throws NullPointerException
     *         如果参数{@code sql}或{@code mapper}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code sql}只包含空白字符。
     */
    <T> Optional<T> querySingle(
            String sql,
            Mapper<T> mapper
    );

    /**
     * 执行更新操作。
     *
     * @param sql
     *         需要执行的SQL语句
     * @return 受影响的记录数
     * @throws NullPointerException
     *         如果参数{@code sql}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code proc}只包含空白字符。
     */
    int update(
            String sql
    );

    /**
     * 调用存储过程执行查询操作。
     *
     * @param <T>
     *         实体对象类型。
     * @param proc
     *         需要执行的存储过程名。
     * @param mapper
     *         用于将查询结果集映射到实体对象的映射类。
     * @return 查询结果列表, 包含所有被映射的实体类，如果没有记录则返回空列表。
     * @throws NullPointerException
     *         如果参数{@code proc}或{@code mapper}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code proc}只包含空白字符。
     */
    <T> List<T> queryProc(
            String proc,
            Mapper<T> mapper
    );

    /**
     * 执行SQL查询并获取单个实体。
     *
     * @param <T>
     *         实体对象类型。
     * @param proc
     *         需要执行的存储过程名。
     * @param mapper
     *         用于将查询结果集映射到实体对象的映射类。
     * @return 查询结果, 即使查询结果集包含多条记录也只返回第一个实体, 如果没有记录则返回{@code Optional.empty}。
     * @throws NullPointerException
     *         如果参数{@code proc}或{@code mapper}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code proc}只包含空白字符。
     */
    <T> Optional<T> querySingleProc(
            String proc,
            Mapper<T> mapper
    );

    /**
     * 调用存储过程执行更新操作。
     *
     * @param proc
     *         需要执行的存储过程名。
     * @return 受影响的记录数
     * @throws NullPointerException
     *         如果参数{@code proc}是{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code proc}只包含空白字符。
     */
    int updateProc(
            String proc
    );

    /**
     * 获取最后修改的记录的ID。
     *
     * @return 最后修改的记录的ID。
     */
    Object getLastRowId();
}
